// ValidationAspects
// Written by Mike Saunders
// Released under Microsoft Public License (Ms-PL)
using System;
using System.Reflection;
using NUnit.Framework;
using ValidationAspects;
using ValidationAspects.Sdk.Interception;

namespace TestValidationAspects.Sdk.Interception
{
	[TestFixture]
	public class TestInterceptValidateProperty
	{
		[SetUp]
		public void SetUp()
		{
			TestHelpers.ResetFramework();
		}

		[TestFixtureTearDown]
		public void TestFixtureTearDown()
		{
			TestHelpers.ResetFramework();
		}

		[Test]
		[ExpectedException(typeof(ArgumentNullException))]
		public void Test_InterceptValidateProperty_throws_for_null_PropertyInfo_param()
		{
			InterceptValidate.Property(null, new object(), new object());
		}

		[Test]
		public void Test_InterceptValidateProperty_for_InterceptionValidationMode_throws_caught_ValidationException_and_populates_context()
		{
			MockValidatorFactory<string> factory = new MockValidatorFactory<string>();
			PropertyInfo property = TypeOf<Dummy>.GetProperty(x => x.Property);
			property.ReplaceValidation(new[] {factory});

			factory.Fail = true;

			object instance = new object();
			try
			{
				InterceptValidate.Property(property, instance, "text");
			}
			catch (ValidationException e)
			{
				Assert.AreEqual("failed", e.Message);
				MethodInfo method = property.GetSetMethod();
				e.Context.TestValues(instance, typeof(Dummy), property, method, method.GetParameters()[0], new object[] {"text"});
				return;
			}
			Assert.Fail("ValidationContextException not thrown");
		}

		[Test]
		public void Test_InterceptValidateProperty_for_static_property_and_InterceptionValidationMode_throws_caught_ValidationException_and_populates_context()
		{
			MockValidatorFactory<string> factory = new MockValidatorFactory<string>();
			PropertyInfo property = typeof(Dummy).GetProperty("StaticProperty", BindingFlags.Public | BindingFlags.Static);
			property.ReplaceValidation(new[] {factory});

			factory.Fail = true;

			try
			{
				InterceptValidate.Property(property, null, "text");
			}
			catch (ValidationException e)
			{
				Assert.AreEqual("failed", e.Message);
				MethodInfo method = property.GetSetMethod();
				e.Context.TestValues(null, typeof(Dummy), property, method, method.GetParameters()[0], new object[] {"text"});
				return;
			}
			Assert.Fail("ValidationContextException not thrown");
		}

		[Test]
		public void Test_InterceptValidateProperty_for_InterceptionValidationMode_for_no_registered_validator()
		{
			InterceptValidate.Property(TypeOf<Dummy>.GetProperty(x => x.Property), new Dummy(), "text");
		}

		[Test]
		public void Test_InterceptValidateProperty_InterceptionValidationMode()
		{
			MockValidatorFactory<string> factory = new MockValidatorFactory<string>();
			PropertyInfo property = TypeOf<Dummy>.GetProperty(x => x.Property);
			property.ReplaceValidation(new[] {factory});

			object instance = new object();
			InterceptValidate.Property(property, instance, "text");

			Assert.AreEqual("text", factory.Value);
			MethodInfo method = property.GetSetMethod();
			factory.Context.TestValues(instance, typeof(Dummy), property, method, method.GetParameters()[0], new object[] {"text"});
		}

		[Test]
		public void Test_InterceptValidateProperty_for_non_InterceptionValidationMode_does_not_throw()
		{
			ValidationSettings.InterceptValidateProperties = false;

			MockValidatorFactory<string> factory = new MockValidatorFactory<string>();
			TypeOf<Dummy>.GetProperty(x => x.Property).ReplaceValidation(new[] {factory});

			factory.Fail = true;

			object instance = new object();
			InterceptValidate.Property(TypeOf<Dummy>.GetProperty(x => x.Property), instance, "text");
		}

		[Test]
		public void Test_InterceptValidateProperty_for_non_InterceptionValidationMode()
		{
			ValidationSettings.InterceptValidateProperties = false;

			MockValidatorFactory<string> factory = new MockValidatorFactory<string>();
			TypeOf<Dummy>.GetProperty(x => x.Property).ReplaceValidation(new[] {factory});

			object instance = new object();
			InterceptValidate.Property(TypeOf<Dummy>.GetProperty(x => x.Property), instance, "text");

			Assert.IsNull(factory.Value);
			Assert.IsNull(factory.Context);
		}

		#region Mocks
		public class Dummy
		{
			public string Property { get; set; }
			public static string StaticProperty { get; set; }
		}
		#endregion
	}
}